package kisti.module.Notification;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.net.Socket;
import java.util.ArrayList;
import java.util.StringTokenizer;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import kisti.module.log.Glog;

import org.apache.commons.mail.EmailException;
import org.apache.commons.mail.SimpleEmail;
import org.w3c.dom.Document;
import org.w3c.dom.Element;


/**
 * <pre>
 * kisti.module.log
 *   |_ Notification.java
 *
 * </pre>
 *
 * Desc : 시스템 알람 모듈, 시스템에 문제나 신호 발생시 등록된 사용자에게 E-mail 과 sms 으로 전송한다.
 * @Company : KISTI
 * @Author :daniel
 * @Date   :2012. 1. 26. 오전 10:57:00
 * @Version:
 *
 */
public class Notification implements Runnable{


	// 134.75.123.33 ce
	private static final String IPADDR_DANIEL_SERVER = "150.183.234.168";
	private static final String IPADDR_SAM = "sam0.sdfarm.kr";
	private static final String IPADDR_CE03 = "ce03.sdfarm.kr";
	private static final int PORT = 9734;

	private Socket socket;
	private BufferedInputStream bis;
	// private BufferedOutputStream bos;
	private InputStreamReader isr;
	private BufferedReader reader;
	private DataOutputStream dos;
	
	
	//member variable 
	private Double ce03Cpu;
	private Double ce03MemTotal;
	private Double ce03MemUse;
	
	private Double samCpu;
	private Double samMemTotal;
	private Double samMemUse;
	
	private Double cdf01Disk;
	private Double cdf02Disk;
	private Double cdfGeneralDisk;
	
	
	private static final int ONE_SEC = 1000;
	private static final int ONE_MIN = 60*1000;
	private static final int ONE_HOUR = 60*60*1000;
	
//	private static boolean DEBUG = false;
	
	public Notification() {
		// TODO Auto-generated constructor stub
		
		Thread t = new Thread(this);
		t.start();
		
	}
	

	@Override
	public void run() {
		// TODO Auto-generated method stub
		
		while (true) {			
			try {
				notificationModule();				
				
				Thread.sleep(ONE_HOUR*1); //1000 : 1초								
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				System.out.println(e.toString());
			}					
		}
	}
	
	
	private void notificationModule(){
		/**
		 * 1. 30초마다 실행
		 * 2. 해당 컨디션 함수 콜
		 * 3. 컨디션 체크 후, 해당 notification 함수 호출하여 메시지 전송 
		 */

		/**- 실시간 체크
		 * 1. G-man Server Errors (Glog 에서 해당 함수 직접 호출)
		 * 
		 * - 60분 마다 확인
		 * 2. CE03 CPU 50% 이상 사용시
		 * 3. CE03 MEM 50% 이상 사용시
		 * 4. SAM Station Disk 사용률 95%이상
		 *  
		 */
		
		/**
		 * 먼저 데이터를 요청한다
		 */
		checkCE03();
		checkSamStation();
		
		

		/**
		 * ce03 check 
		 */
		if (ce03Cpu < 50) { //cpu idle 이 50% 이하일 경우			
			sender_email("[Warning!!] CE03 has more then 50% of cpu usage");
			sender_sms  ("[Warning!!] CE03 has more then 50% of cpu usage");
		}
		if (  (ce03MemUse/ce03MemTotal) > 0.5 ) { //mem 사용률이 50% 이상일 경우			
			sender_email("[Warning!!] CE03 has more then 50% of memory usage");
			sender_sms  ("[Warning!!] CE03 has more then 50% of memory usage");
		}
		/**
		 * sam station check 
		 */
		if (  samCpu < 50) { //cpu idle 이 50% 이하일 경우			
			sender_email("[Warning!!] Sam Station has more then 50% of cpu usage");
			sender_sms  ("[Warning!!] Sam Station has more then 50% of cpu usage");
		}
		if ( (samMemUse/samMemTotal) > 0.5 ) { //mem 사용률이 50% 이상일 경우			
			sender_email("[Warning!!] Sam Station has more then 50% of memory usage");
			sender_sms  ("[Warning!!] Sam Station has more then 50% of memory usage");
		}
		if (  cdf01Disk > 95) { //cdf01Disk 사용률이 95% 이상일 경우			
			sender_email("[Warning!!] CDF01 has more then 95% of cpu usage");
			sender_sms  ("[Warning!!] CDF01 has more then 95% of cpu usage");
		}
		if (  cdf02Disk > 95 ) { //cdf02Disk 사용률이 95% 이상일 경우			
			sender_email("[Warning!!] CDF02 has more then 95% of cpu usage");
			sender_sms  ("[Warning!!] CDF02 has more then 95% of cpu usage");
		}
		if (  cdfGeneralDisk > 95) { //cdfGeneralDisk 사용률이 95% 이상일 경우			
			sender_email("[Warning!!] home-osg has more then 95% of cpu usage");
			sender_sms  ("[Warning!!] home-osg has more then 95% of cpu usage");
		}
		
	}
	
	
	/**
	 * 
	 * Desc : Sam 서버에서 메모리, CPU, 디스크, 네트워크 사용 정보를 가져온다
	 * @Method Name : getSamInfo
	 * @return CPU, Memory, Disk , Network 사용정보를 XML 형태로 생성하여 반환
	 *
	 */
	private Object checkCE03() {
		Glog.Log(Glog.LOG_COMMON,"Notification" ,"checkCE03 ");
		Object obj = null;

		try {
			openServer(IPADDR_CE03);
			

			int n = 16;			n <<= 8;			n |= 1;
			String s = Integer.toString(n);
			byte[] b = s.getBytes();

			
			String cmdString = "cat /proc/meminfo | sed '3,$d' | awk '{print $2\" \"}';  "
				+ "dstat 1 1 | sed '1,3d'  | awk  '{print $3}' ; \0";






			dos.write(b, 0, b.length);
			dos.write(cmdString.getBytes(), 0, cmdString.getBytes().length);

			char[] cbuf = new char[1024];

			String resultData = "";
			while (reader.read(cbuf, 0, 1024) != -1) {
				String str = new String(cbuf);
				str = str.trim();
				str += " ";

				resultData += str;

				for (int i = 0; i < 1024; i++)
					cbuf[i] = '\0';
			}
			

			
			
			StringTokenizer st = new StringTokenizer(resultData, " ");
			System.out.println(resultData);
			
			ce03MemTotal = Double.parseDouble(st.nextToken());
			ce03MemUse = Double.parseDouble(st.nextToken());
			ce03Cpu = Double.parseDouble(st.nextToken());
//	
						
		

			
			
			dos.close();

			closeServer();
		} catch (Exception e) {
			Glog.Log(Glog.LOG_ERROR,"Notification" , e.toString());
		}

		return obj;
	}
	
	
	/**
	 * 
	 * Desc : Sam 서버에서 메모리, CPU, 디스크, 네트워크 사용 정보를 가져온다
	 * @Method Name : getSamInfo
	 * @return CPU, Memory, Disk , Network 사용정보를 XML 형태로 생성하여 반환
	 *
	 */
	private Object checkSamStation() {
		Glog.Log(Glog.LOG_COMMON,"Notification" ,"checkCE03 ");
		Object obj = null;

		try {
			openServer(IPADDR_SAM);
			

			int n = 16;			n <<= 8;			n |= 1;
			String s = Integer.toString(n);
			byte[] b = s.getBytes();

			
			String cmdString = "cat /proc/meminfo | sed '3,$d' | awk '{print $2\" \"}';  \\"
				+ "dstat 1 1 | sed '1,3d'  | awk  '{print $3}'  ;"
			+ "df -h | grep cdf | awk '{print $5}' ;"
			+ "df -h | grep home-osg | awk '{print $4}' ; \0";

			dos.write(b, 0, b.length);
			dos.write(cmdString.getBytes(), 0, cmdString.getBytes().length);

			char[] cbuf = new char[1024];

			String resultData = "";
			while (reader.read(cbuf, 0, 1024) != -1) {
				String str = new String(cbuf);
				str = str.trim();
				str += " ";

				resultData += str;
//				resultData = resultData.replace("|", " ");

				for (int i = 0; i < 1024; i++)
					cbuf[i] = '\0';
			}
			
			resultData = resultData.replace("%", " ");

			System.out.println(resultData);
			
			StringTokenizer st = new StringTokenizer(resultData, " ");
			
			samMemTotal = Double.parseDouble(st.nextToken());
			samMemUse = Double.parseDouble(st.nextToken());
			samCpu = Double.parseDouble(st.nextToken());
			cdf01Disk = Double.parseDouble(st.nextToken());
			cdf02Disk = Double.parseDouble(st.nextToken());
			cdfGeneralDisk = Double.parseDouble(st.nextToken());
		

			
			
			dos.close();

			closeServer();
		} catch (Exception e) {
			Glog.Log(Glog.LOG_ERROR,"Notification" , e.toString());
		}

		return obj;
	}
	
	
	/**
	 * 
	 * Desc : 연결할 서버 소켓을 연다. 연결이 완료되면
	 * 해당 정보를 전역 sock 정보에 담아둔다. 
	 * @Method Name : openServer 
	 * @param IPADDR 연결할 서버의 ip 주소
	 *
	 */
	private void openServer(String IPADDR) {
		Glog.Log(Glog.LOG_COMMON,"Notification" ,"open Server() ");
		try {
			socket = new Socket(IPADDR, PORT);			
			dos = new DataOutputStream(socket.getOutputStream());
			dos.flush();
			reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));			
		} catch (Exception e) {
			e.printStackTrace();
			Glog.Log(Glog.LOG_ERROR,"Notification" , "ConnectoServer : "+IPADDR);
			Glog.Log(Glog.LOG_ERROR,"Notification" , e.toString());			
		}
	}

	/**
	 * 
	 * Desc : 연결할 서버 소켓을 닫는다. 
	 * @Method Name : closeServer
	 *
	 */
	private void closeServer() {
		try {
			dos.close();
			reader.close();
			socket.close();
			Glog.Log(Glog.LOG_COMMON,"Notification" ,"close Server() ");
		} catch (Exception e) {
			Glog.Log(Glog.LOG_ERROR,"Notification" , e.toString());
		}
	}

	
	
	
	
	/**
	 * 
	 * Desc :
	 * @Method Name : smsSender
	 *
	 */
	public void sender_sms(String messages){
		SMS sms = new SMS();

        /**
         * 프로그램명과 버젼을 입력합니다. (생략가능합니다.)
         * 형식: 프로그램명/버젼 (프로그램명: 반드시 영어로, 버젼: x.x.x 와 같은 형식)
         * 입력예: TEST/1.0
         **/
        sms.appversion("TEST/1.0");

        // 한글 인코딩 방식을 설정합니다. (utf8 혹은 euckr으로 설정, 생략시 기본 euckr로 설정됨)
        sms.charset("utf8");

        // 아이디/비밀번호를 설정합니다. (쿨에스엠에스(www.coolsms.co.kr)에서 가입하신 아이디, 비밀번호를 넣어줍니다.)
//        sms.setuser("coolsms-id", "coolsms-pass");
        sms.setuser("yagi815", "rudfbs00");
        

        /**
         * 문자 추가
         * 1) 최대 보낼 수 있는 문자의 길이는 80바이트이며 초과시 80바이트 이내 문자만 전송됩니다.
         * 2) 갯수에 제한없이 add 호출로 보낼 문자목록에 계속 추가할 수 있습니다.(send 호출시 모두 전송됩니다.)
         **/
        SmsMessagePdu pdu = new SmsMessagePdu();

		// SMS, LMS, MMS	
        if (messages.length() > 80) {
			pdu.type = "MMS";
		}else{
			pdu.type = "SMS";
		}
        

        pdu.destinationAddress = "01037588197";  // 수신번호
        pdu.scAddress = "0200000000";            // 발신번호
        pdu.text = messages;
        
        
        sms.add(pdu);

        
        // 추가된 메세지 전송
        try {
            sms.connect();
            sms.send();
            sms.disconnect();
        } catch (Exception e) {
        	e.printStackTrace();
            System.out.println(e.toString());
        }

        // 전송 결과 출력
        sms.printr();

        // 추가된 메세지 및 전송결과 데이터를 메모리에서 제거합니다.
        sms.emptyall();
		
	}
	
	
	/**
	 * 
	 * Desc :
	 * @Method Name : emailSender
	 *
	 */
	public void sender_email(String messages) {
		System.out.println("hello");

		SimpleEmail email = new SimpleEmail();

		try {
			email.setCharset("euc-kr");
			email.setHostName("localhost");
			email.addTo("grkim@kisti.re.kr", "accepter");
			email.setFrom("grkim@kisti.re.kr", "G-man TierServer");
			email.setSubject("[G-man Nitification]");

			System.out.println("mail Contents: " + messages);
//			email.setMsg("Email message test from java app.......... ");
			email.setMsg(messages);

			
			String retMessage = email.send();
			System.out.println(retMessage);

		} catch (EmailException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			System.out.println(e.toString());
		}
	}
	
	public static void main(String[] args) {

		Notification e = new Notification();

		
	}
}
